package Partie1;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import commun.Review;

/**
 * 
 * @author Yangkun, Chengbo
 * Un parseur pour le modèle de berboulli
 */
public class BernoulliParser {
	public static char[] points= {'.',',','\'','\"','+','=','-','@','#','$','%','<','>','!','?','[',']','(',')',':',';','*','/','&','0','1','2','3','4','5','6','7','8','9','','~','\r','\n','_'};
	public static String[] stopWords = {"a", "about", "above", "above", "across", "after", "afterwards", "again", "against", "all", "almost", "alone", "along", "already", "also","although","always","am","among", "amongst", "amoungst", "amount",  "an", "and", "another", "any","anyhow","anyone","anything","anyway", "anywhere", "are", "around", "as",  "at", "back","be","became", "because","become","becomes", "becoming", "been", "before", "beforehand", "behind", "being", "below", "beside", "besides", "between", "beyond", "bill", "both", "bottom","but", "by", "call", "can", "cannot", "cant", "co", "con", "could", "couldnt", "cry", "de", "describe", "detail", "do", "done", "down", "due", "during", "each", "eg", "eight", "either", "eleven","else", "elsewhere", "empty", "enough", "etc", "even", "ever", "every", "everyone", "everything", "everywhere", "except", "few", "fifteen", "fify", "fill", "find", "fire", "first", "five", "for", "former", "formerly", "forty", "found", "four", "from", "front", "full", "further", "get", "give", "go", "had", "has", "hasnt", "have", "he", "hence", "her", "here", "hereafter", "hereby", "herein", "hereupon", "hers", "herself", "him", "himself", "his", "how", "however", "hundred", "ie", "if", "in", "inc", "indeed", "interest", "into", "is", "it", "its", "itself", "keep", "last", "latter", "latterly", "least", "less", "ltd", "made", "many", "may", "me", "meanwhile", "might", "mill", "mine", "more", "moreover", "most", "mostly", "move", "much", "must", "my", "myself", "name", "namely", "neither", "never", "nevertheless", "next", "nine", "no", "nobody", "none", "noone", "nor", "not", "nothing", "now", "nowhere", "of", "off", "often", "on", "once", "one", "only", "onto", "or", "other", "others", "otherwise", "our", "ours", "ourselves", "out", "over", "own","part", "per", "perhaps", "please", "put", "rather", "re", "same", "see", "seem", "seemed", "seeming", "seems", "serious", "several", "she", "should", "show", "side", "since", "sincere", "six", "sixty", "so", "some", "somehow", "someone", "something", "sometime", "sometimes", "somewhere", "still", "such", "system", "take", "ten", "than", "that", "the", "their", "them", "themselves", "then", "thence", "there", "thereafter", "thereby", "therefore", "therein", "thereupon", "these", "they", "thickv", "thin", "third", "this", "those", "though", "three", "through", "throughout", "thru", "thus", "to", "together", "too", "top", "toward", "towards", "twelve", "twenty", "two", "un", "under", "until", "up", "upon", "us", "very", "via", "was", "we", "well", "were", "what", "whatever", "when", "whence", "whenever", "where", "whereafter", "whereas", "whereby", "wherein", "whereupon", "wherever", "whether", "which", "while", "whither", "who", "whoever", "whole", "whom", "whose", "why", "will", "with", "within", "without", "would", "yet", "you", "your", "yours", "yourself", "yourselves", "the","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","\r\n"};
	public Map<String, Double> PositiveTable;
	public Map<String, Double> NegativeTable;
	private Map<String, Integer> Negatifwords;
	private Map<String, Integer> Positifwords;
	private double lissage;
	private long nbDocPositif, nbDocNegatif;
	/**
	 * Constructeur
	 */
	public BernoulliParser() {
		lissage = 0.5;
		Negatifwords = new HashMap<String, Integer>();
		Positifwords = new HashMap<String, Integer>();
		NegativeTable = new HashMap<String, Double>();
		PositiveTable = new HashMap<String, Double>();
		nbDocPositif=0;
		nbDocNegatif=0;
	}
	/**
	 * Point d'accès pour commencer à parser le ficheir de trainng
	 * @param filepath l'adresse de fichier à analyser
	 * @throws Exception
	 */
	public  void parseFile(String filepath) throws Exception{
		File f = new File(filepath); 
		FileInputStream fstream = new FileInputStream(f);
		DataInputStream in = new DataInputStream(fstream);		
		BufferedReader br = new BufferedReader(new InputStreamReader(in));
		String strLine;
	    while ((strLine = br.readLine()) != null)   {
	    	if(strLine.contains("<review") && strLine.contains("id"))
			{
	    		Review unReview = BernoulliParser.parseUnReview(br, strLine); 
	    		Iterator iter = unReview.wordsMap.entrySet().iterator();
	    		if(unReview.realType == commun.ReviewType.Negative)
	    		{
	    			this.nbDocNegatif++;
	    			while (iter.hasNext()) { 
				    	Map.Entry entry = (Map.Entry) iter.next();
				        String key = (String)entry.getKey(); 
				        if(this.Negatifwords.containsKey(key))
				        {
				        	Integer val = (Integer)Negatifwords.get(key);
			        		val++;
			        		Negatifwords.put(key,val);
				        }
				        else
				        {
				        	Negatifwords.put(key, 1);
				        }
				    }    			
	    		}
	    		else
	    		{
	    			this.nbDocPositif++;
	    			while (iter.hasNext()) { 
				    	Map.Entry entry = (Map.Entry) iter.next();
				        String key = (String)entry.getKey(); 
				        if(this.Positifwords.containsKey(key))
				        {
				        	Integer val = (Integer)Positifwords.get(key);
			        		val++;
			        		Positifwords.put(key,val);
				        }
				        else
				        {
				        	Positifwords.put(key, 1);
				        }
				    }
	    		}
			}
	    }
	    br.close();
	    in.close();
	    fstream.close(); 
	    
	    FormerTable();
	}
	/**
	 * Cette méthode est utilisé pour établir les deux tables
	 * @throws IOException
	 */
	public void FormerTable() throws IOException
	{
	    calculProbabilite();
		//wirteTable();
	}
	/**
	 * parser tous les review dans le fichier.
	 * @param filepath o� se trouve le fichier �tudi�
	 * @throws Exception
	 */
	public static Review parseUnReview(BufferedReader br, String firstLine) throws IOException
	{
		String strLine;
		ArrayList<String> lst = new ArrayList<String>(); 
		lst.add(firstLine);
	    while ((strLine = br.readLine()) != null)   {
	    	lst.add(strLine);
	    	if(strLine.contains("</review>"))
	    	{
	    		break;
	    	}
	    }
	    return new Review(lst);
	}

	/**
	 * Calculer la probabilité de chaque mot de la table
	 */
	private void calculProbabilite()
	{
		Iterator iterNegatif = Negatifwords.entrySet().iterator();
		Iterator iterPositif = Positifwords.entrySet().iterator();
		double valNegatif = this.lissage/this.nbDocNegatif;
    	Double valueNegatif = new Double(valNegatif);
    	double valPositif = this.lissage/this.nbDocPositif;
    	Double valuePositif = new Double(valPositif);
		while (iterNegatif.hasNext()) { 
	    	Map.Entry entry = (Map.Entry)iterNegatif.next();
	        String key = (String)entry.getKey(); 
	        //ajouter key au Negatiftable
	        double val;
	        if(((Integer)entry.getValue()) == nbDocNegatif)
	        {
	        	val= (double)(((Integer)entry.getValue()).floatValue() - 1)/(double)nbDocNegatif;
	        }
	        else
	        {
	        	val= (double)(((Integer)entry.getValue()).floatValue())/(double)nbDocNegatif;
	        }
	        Double value = new Double(val);
	        this.NegativeTable.put(key, value);
	        //ajouter key au Positiftable
	        //if(PositifTable.containsKey())
	    }
	    while (iterPositif.hasNext()) { 
	    	Map.Entry entry = (Map.Entry)iterPositif.next();
	        String key = (String)entry.getKey(); 
	        //ajouter key au Negatiftable
	        double val;
	        if(((Integer)entry.getValue()) == this.nbDocPositif)
	        {
	        	val= (double)(((Integer)entry.getValue()).floatValue() - 1)/(double)nbDocPositif;
	        }
	        else
	        {
	        	val= (double)(((Integer)entry.getValue()).floatValue())/(double)nbDocPositif;
	        }
	        
	        Double value = new Double(val);
	        this.PositiveTable.put(key, value);
	        //ajouter key au Negatiftable
	        if(!this.NegativeTable.containsKey(key))
	        {	
	        	NegativeTable.put(key, valueNegatif);
	        }
	    }
	    iterNegatif = Negatifwords.entrySet().iterator();
	    while (iterNegatif.hasNext()) { 
	    	Map.Entry entry = (Map.Entry) iterNegatif.next();
	        String key = (String)entry.getKey(); 
	        if(!this.PositiveTable.containsKey(key))
	        {	
	        	PositiveTable.put(key, valuePositif);
	        }
	    }
	}
	
	/**
	 * Celle nous permet d'écrir les tables au fichier
	 * @throws IOException
	 */
	public void wirteTable() throws IOException{
		FileWriter fwNegatif = new FileWriter("NegatifBernoulli.txt");//
        BufferedWriter bwNegatif = new BufferedWriter(fwNegatif);    //
        FileWriter fwPositif = new FileWriter("PositifBernoulli.txt");//
        BufferedWriter bwPositif = new BufferedWriter(fwPositif);    //
        String myreadline = new String();    //
        
		Iterator iterNegatif = this.NegativeTable.entrySet().iterator();
		Iterator iterPositif = this.PositiveTable.entrySet().iterator();
		//write Negatif
		while (iterNegatif.hasNext()) { 
	    	Map.Entry entry = (Map.Entry) iterNegatif.next();
	        String key = (String)entry.getKey();
	        myreadline = key+ " : "+ ((Double)entry.getValue()).toString();
	        bwNegatif.write(myreadline); //
            bwNegatif.newLine();
		}
		//wirte no Negatif
		while (iterPositif.hasNext()) { 
	    	Map.Entry entry = (Map.Entry) iterPositif.next();
	        String key = (String)entry.getKey(); 
	        myreadline = key+ " : "+ ((Double)entry.getValue()).toString();
	        bwPositif.write(myreadline); //
            bwPositif.newLine();
	     }
		bwNegatif.flush();    //
        bwNegatif.close();
        fwNegatif.close();
        
        bwPositif.flush();    //
        bwPositif.close();
        fwPositif.close();
	}
	
}
